package org.redmaple.core.util;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
 * 对象中的属性转换辅助工具
 * @author Xiangyun
 *
 */
public final class Data7ViewerConvert {

	public static final String SET_METHOD_PREFIX = "set";
	public static final String GET_METHOD_PREFIX = "get";

	protected static Logger logger = LoggerFactory
			.getLogger(Data7ViewerConvert.class);

	/**
	 * 利用Java的放射机制，将源对象与目标对象中相同的属性进行转换
	 * 
	 * @param sourceObj
	 *            源对象
	 * @param targetObj
	 *            目标对象
	 * @return 目标对象
	 * @throws NoSuchMethodException
	 *             若源对象与目标对象中相同的属性，其中源对象不提供get方法或目标对象不提供set方法，将会抛出此异常
	 */
	@SuppressWarnings("unchecked")
	public static <X extends Serializable> X convert(Serializable sourceObj,
			Serializable targetObj) throws NoSuchMethodException {
		Assert.notNull(targetObj);
		Assert.notNull(sourceObj);
		Field[] sourceFields = sourceObj.getClass().getDeclaredFields();
		Field[] targetFields = targetObj.getClass().getDeclaredFields();
		String fileldName = null;
		for (Field sourceField : sourceFields) {
			fileldName = sourceField.getName();
			for (Field targetField : targetFields) {
				if (fileldName.equals(targetField.getName())) {
					metadataConvert(sourceObj, sourceField, targetObj,
							targetField);
					break;
				}
			}
		}
		return (X) targetObj;
	}

	private static void metadataConvert(Serializable sourceObj,
			Field sourceField, Serializable targetObj, Field targetField)
			throws NoSuchMethodException {
		String fieldName = targetField.getName();
		String setMethod = new StringBuffer().append(SET_METHOD_PREFIX)
				.append(fieldName.substring(0, 1))
				.append(fieldName.substring(1)).toString();
		String getMethod = new StringBuffer().append(GET_METHOD_PREFIX)
				.append(fieldName.substring(0, 1))
				.append(fieldName.substring(1)).toString();
		Method targerMethod = targetObj.getClass().getDeclaredMethod(setMethod,
				targetField.getType());
		Method sourceMethod = targetObj.getClass().getDeclaredMethod(getMethod,
				targetField.getType());
		try {
			if (targetField.getType().equals(sourceField.getType())) {
				// 类型保持一致的话，则直接调用
				targerMethod.invoke(targetObj, sourceMethod.invoke(sourceObj));
			} else {
				// 类型不一致的情况下，执行以下转换
				Object value = sourceMethod.invoke(sourceObj);
				if (targetField.getType().equals(String.class)) {
					// 当要转换为字符串时，则直接调用toString()方法
					targerMethod.invoke(targetObj, value.toString());
				} else if (targetField.getType().equals(Date.class)) {
					if (value instanceof String) {
						targerMethod.invoke(targetObj,
								DateUtils.parseToSqlDate((String) value));
					} else {
						throw new ConvertToTimeException(value.getClass()
								.getName() + " 类型的对象不能转换为 java.sql.Date 类型的对象");
					}
				} else if (targetField.getType().equals(Timestamp.class)) {
					if (value instanceof String) {
						targerMethod.invoke(targetObj,
								DateUtils.parseToSqlTimestamp((String) value));
					} else {
						throw new ConvertToTimeException(value.getClass()
								.getName()
								+ " 类型的对象不能转换为 java.sql.Timestamp 类型的对象");
					}
				} else if (targetField.getType().equals(Time.class)) {
					if (value instanceof String) {
						targerMethod.invoke(targetObj,
								DateUtils.parseToSqlTime((String) value));
					} else {
						throw new ConvertToTimeException(value.getClass()
								.getName() + " 类型的对象不能转换为 java.sql.Time 类型的对象");
					}
				}
			}
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		} catch (InvocationTargetException e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		}
	}
}
